import logging

from flask import Blueprint, current_app
from flask import request
from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity, get_jwt, get_jwt
import re
from datetime import date
from app.models import db, User, Preference, UserBehaviorStats, LTVLevelEnum
import app.utils as utils
import decimal

# flask提供Blueprint用于将一个项目按照功能模块拆分，这样一来路由就不需要全部写在app.py中了
# NOTE 项目开发规范：妥善将项目功能进行拆分，便于分工，常用的做法是根据功能对象，例如所有与user相关的接口都放在user_controller.py文件中
# 如下则是创建了一个名为user_controller的蓝图（固定写法），并返回一个名为user_controller的蓝图对象（将来在app.py中使用它）
user_controller = Blueprint('user_controller', __name__)


# 统一为每个请求打印日志，通过“蓝图.before_request”和“蓝图.after_request”
@user_controller.before_request
def log_request_info():
    current_app.logger.info(f"收到请求: {request.method} {request.url}")
@user_controller.after_request
def log_response_info(response):
    current_app.logger.info(f"响应状态码: {response.status_code}")
    return response


def calculate_ltv(user_behavior: UserBehaviorStats) -> LTVLevelEnum:
    # 安全地提取值 - 不进行类型转换
    total_login = user_behavior.total_login_count
    total_transactions = user_behavior.total_transactions
    total_commission = user_behavior.total_commission
    print(f"total_login:{total_login}", flush=True)
    print(f"total_transactions:{total_transactions}", flush=True)
    print(f"total_commission:{total_commission}", flush=True)
    # 处理可能的 None 值
    if total_login is None:
        total_login = 0
    if total_transactions is None:
        total_transactions = 0
    if total_commission is None:
        total_commission = 0.0

    # 确保所有值都是 Python 基本类型
    # 不需要 int() 转换，直接使用
    total_login = total_login if isinstance(total_login, (int, float)) else 0
    total_transactions = total_transactions if isinstance(total_transactions, (int, float)) else 0
    total_commission = float(total_commission) if isinstance(total_commission, (int, float, decimal.Decimal)) else 0.0
    print(f"total_login:{total_login}", flush=True)
    print(f"total_transactions:{total_transactions}", flush=True)
    print(f"total_commission:{total_commission}", flush=True)
    total_login = total_login + 1
    # 1. 计算注册天数
    reg_date = user_behavior.registration_date
    days_registered = (date.today() - reg_date).days
    if days_registered <= 0:
        days_registered = 1  # 避免除零错误

    # 2. 计算活跃度系数
    daily_login_freq = total_login / days_registered
    daily_trans_freq = total_transactions / days_registered

    # 确保计算实际数值
    activity_value = 0.4 * daily_login_freq + 0.6 * daily_trans_freq
    activity_coeff = min(1.5, activity_value)

    # 3. 计算年化预期佣金收益
    annual_commission = total_commission * 365 / days_registered

    # 4. 计算LTV
    ltv_value = activity_coeff * annual_commission
    print(f"ltv:{ltv_value}",flush=True)
    # 5. 确定等级
    if ltv_value <= 30000:
        return LTVLevelEnum.LOW
    elif 30000 < ltv_value <= 100000:
        return LTVLevelEnum.MEDIUM
    else:
        return LTVLevelEnum.HIGH

ltv_mapping = {
    LTVLevelEnum.LOW: "普通用户",
    LTVLevelEnum.MEDIUM: "白银用户",
    LTVLevelEnum.HIGH: "黄金用户"
}

# 使用蓝图之后，定义路由的方式稍微有些变化（仅在于从app变成了对应的Blueprint而已）
# NOTE RESTful风格规范：在定义接口时要根据接口功能选择合适请求方式：GET用于查询、POST用于操作或新增、PUT用于更新、DELETE用于删除等
@user_controller.post('/login')
def user_login():
    print("1",flush=True)
    """
    处理用户登录
    """
    # 获取用户数据并校验参数
    login_data = request.get_json()
    username, password = login_data['username'], login_data['password']
    if not username or not password:
        return utils.error("参数不合法")
    print("2", flush=True)
    # 根据username查询出对应记录，由于我们知道username一定是唯一的，所以直接取第一个即可
    db_user = db.session.query(User).filter_by(username=username).first()
    # 验证username是否存在，并且验证传入的密码是否与数据库中的密码“一致”
    if not db_user or not utils.check(password, db_user.password):
        return utils.error(message="用户名或密码不正确", code=401)
    print("3", flush=True)
    behavior_stats = UserBehaviorStats.query.filter_by(user_id=db_user.id).first()

    behavior_stats.ltv = calculate_ltv(behavior_stats)
    behavior_stats.total_login_count = UserBehaviorStats.total_login_count + 1
    user_level = ltv_mapping.get(behavior_stats.ltv, "未知用户")
    # 到此验证成功
    # 创建jwt，这里需要使用强转（因为identity要求传入的参数必须为str），额外的信息可以通过additional_claims来获得，切记不要传入password
    token = create_access_token(identity=str(db_user.id), additional_claims={"user_info": {
        "id": db_user.id,
        "username": db_user.username,
        "nickname": db_user.nickname,
        "email": db_user.email,
        "phone": db_user.phone,
        "ltv": user_level
    }})
    # 只需要返回code=200即可
    print("4", flush=True)
    ##
    # behavior_stats = UserBehaviorStats.query.filter_by(user_id=db_user.id).first()
    # behavior_stats.total_login_count = UserBehaviorStats.total_login_count + 1
    # behavior_stats.ltv = calculate_ltv(behavior_stats)
    db.session.commit()  # 别忘了commit
    print("heeee", flush=True)
    return utils.success(data=token)


@user_controller.post('/logout')
# jwt_required装饰器，添加了该装饰器的controller要求必须携带jwt令牌，并且在controller内部可以通过get_jwt_identity()获取之前存储在其中的用户信息（本例中是id）
@jwt_required()
def user_logout():
    """
    处理用户登出，如果后端实现需要用到Redis，所以这里实际上只返回一个200，具体由前端实现
    """
    # Flask框架提供了current_app变量在其他蓝图中输出日志
    current_app.logger.info("用户id=%s", get_jwt_identity())
    return utils.success()


def validate_register_data(register_data):
    """
    校验注册数据的工具函数
    :param register_data: Dict 前端提交的用户注册的数据
    :return: 数据是否满足校验标准
    """
    # 定义校验邮箱和中国大陆手机号的正则表达式
    email_pattern = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
    phone_pattern = r'^1[3-9]\d{9}$'
    # 主要是校验各个字段不能为空，并且长度介于1~255之间
    if not "username" in register_data or not "password" in register_data or not "phone" in register_data or not "email" in register_data or not "phone" in register_data:
        return False
    if not register_data["username"] or len(register_data["username"]) > 255 or not register_data["password"] or len(register_data["password"]) > 255 or not register_data["nickname"] or len(register_data["nickname"]) > 255 or not register_data["email"] or re.match(email_pattern, register_data["email"]) is None or not register_data["phone"] or re.match(phone_pattern, register_data["phone"]) is None:
        return False
    return True

@user_controller.post('/register')
def user_register():
    """
    处理用户注册
    """
    # 获取数据
    register_data = request.get_json(force=True)
    # NOTE 更规范的做法是使用类似于marshmallow的参数校验库，但为了方便上手这里采用手动校验
    if not validate_register_data(register_data):
        # 校验失败则返回
        return utils.error("参数不合法")
    user = User(username=register_data['username'], password=register_data['password'], email=register_data['email'], nickname=register_data['nickname'], phone=register_data['phone'])
    # 为password加密
    user.password = utils.encrypt(user.password)
    # 操作数据库
    db.session.add(user)

    ##


    db.session.flush()  # 生成用户ID但不提交事务

    # 创建用户行为统计记录
    behavior_stats = UserBehaviorStats(
        user_id=user.id,  # 使用刚生成的用户ID
        registration_date=date.today(),  # 当前日期作为注册日期
        total_login_count=0,  # 初始登录次数为0
        total_transactions=0,  # 初始交易次数为0
        total_commission=0.00,  # 初始佣金为0
        ltv=LTVLevelEnum.LOW  # 默认设置为低价值等级
    )

    # 添加行为统计记录
    db.session.add(behavior_stats)


    ##
    db.session.commit() # 别忘了commit
    # 返回操作成功
    return utils.success()

@user_controller.get('/info')
@jwt_required()
def user_info():
    print("user_info", flush=True)
    user_id = get_jwt_identity()
    if not user_id:
        return utils.error("用户状态异常", code=401)
    db_user = db.session.query(User).filter_by(id=user_id).first()
    if not db_user:
        return utils.error("用户不存在", code=404)
    behavior_stats = UserBehaviorStats.query.filter_by(user_id=db_user.id).first()
    data = {
        "username": db_user.username,
        "nickname": db_user.nickname,
        "email": db_user.email,
        "phone": db_user.phone,
        "ltv": behavior_stats.ltv
    }
    # print(data)
    # current_app.logger.info(f"ltv: {behavior_stats.ltv}")
    # # 强制刷新输出缓冲区（适用于某些环境）
    print(data, flush=True)

    # 确保日志输出（即使 print 不可见）
    current_app.logger.debug(f"User Data: {data}")
    return utils.success(data=data)




@user_controller.route('/preferences', methods=['GET', 'POST'])
@jwt_required()
def user_preferences():
    user_id = get_jwt_identity()
    if not user_id:
        return utils.error("用户状态异常", code=401)

    try:
        if request.method == 'GET':
            # 查询用户风险偏好数据
            db_preferences = db.session.query(Preference).filter_by(userid=user_id).first()
            if not db_preferences:
                return utils.error("无该用户风险偏好信息", code=404)
            data = {
                "riskpreference": db_preferences.riskpreference.value,
                "exp": db_preferences.exp,
                "maxloss": db_preferences.maxloss,
                "revenue": db_preferences.revenue,
                "goal": db_preferences.goal
            }
            current_app.logger.info(f"获取用户{user_id}的风险偏好信息成功")
            return utils.success(data=data)

        elif request.method == 'POST':
            # 提交问卷数据并生成风险偏好
            preference_data = request.get_json(force=True)
            exp = preference_data.get('exp')
            maxloss = preference_data.get('maxloss')
            revenue = preference_data.get('revenue')
            goal = preference_data.get('goal')

            # 验证数据
            if not all([exp, maxloss, revenue, goal]):
                return utils.error("问卷数据不完整", code=400)

            # 查找是否已有记录
            existing_preference = db.session.query(Preference).filter_by(userid=user_id).first()

            # 如果存在，更新记录
            if existing_preference:
                existing_preference.exp = exp
                existing_preference.maxloss = maxloss
                existing_preference.revenue = revenue
                existing_preference.goal = goal
            else:
                # 如果不存在，创建新记录
                existing_preference = Preference(userid=user_id, exp=exp, maxloss=maxloss, revenue=revenue, goal=goal)
                db.session.add(existing_preference)

            # 计算风险偏好
            avg_score = (exp + maxloss + revenue + goal) / 4
            if avg_score <= 1.75:
                existing_preference.riskpreference = '低风险'
            elif avg_score <= 2.75:
                existing_preference.riskpreference = '中风险'
            else:
                existing_preference.riskpreference = '高风险'

            # 提交到数据库
            db.session.commit()

            # 返回风险偏好信息
            data = {
                "riskpreference": existing_preference.riskpreference.value,
                "exp": existing_preference.exp,
                "maxloss": existing_preference.maxloss,
                "revenue": existing_preference.revenue,
                "goal": existing_preference.goal
            }
            current_app.logger.info(f"用户{user_id}提交风险偏好信息成功")
            return utils.success(data=data)
    except Exception as e:
        current_app.logger.error(f"获取风险偏好信息时发生错误: {str(e)}")
        return utils.error("服务器内部错误", code=500)
    

